import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:share_fit/app/helper/ext/tr_ext.dart';
import 'package:share_fit/app/models/home/date_type_enum.dart';
import 'package:share_fit/app/models/home/sleep_model.dart';
import 'package:share_fit/app/tools/color_const.dart';
import 'package:share_fit/app/tools/date_tool.dart';
import 'package:share_fit/generated/locales.g.dart';

class SleepStackedChart extends StatefulWidget {
  SleepStackedChart({super.key, List<SleepSummary>? summaryList, this.dateType = DateType.day}) : summaryList = summaryList ?? [];

  final List<SleepSummary> summaryList;
  final DateType dateType;

  @override
  State<SleepStackedChart> createState() => _SleepStackedChartState();
}

class _SleepStackedChartState extends State<SleepStackedChart> {
  late Set titles = <dynamic>{};

  int touchedGroupIndex = -1;
  int touchedGroupRodIndex = -1;
  bool isTouched = false;

  List<int> showingTooltipOnBars = [];

  /// 深睡
  final Color deepSleepColor = const Color.fromRGBO(110, 43, 182, 1);

  /// 浅睡
  final Color lightSleepColor = const Color.fromRGBO(152, 92, 247, 1);

  /// 清醒
  final Color awakeColor = const Color.fromRGBO(255, 196, 67, 1);

  /// 快速眼动
  final Color remColor = const Color.fromRGBO(40, 255, 253, 1);

  /// 零星小睡
  final Color napsColor = const Color.fromRGBO(253, 56, 197, 1);

  @override
  Widget build(BuildContext context) {
    titles = widget.summaryList.map((e) => e.calendar).toSet();
    bool noData = !widget.summaryList.any((e) => e.models.isNotEmpty && e.models.any((element) => (element.sleepTime ?? 0) > 0));

    return noData
        ? Center(child: Text(LocaleKeys.no_records_text.ts))
        : AspectRatio(
            aspectRatio: 1.66,
            child: Padding(
              padding: EdgeInsets.symmetric(horizontal: 30.w),
              child: LayoutBuilder(builder: (context, constraints) {
                final barsSpace = 70.0 * constraints.maxWidth / 400 * titles.length;
                final barsWidth = 14.0 * constraints.maxWidth / 400;

                List<BarChartGroupData> bars = getBarGroupsData(barsWidth, barsSpace);
                return BarChart(
                  // swapAnimationDuration: const Duration(milliseconds: 500),
                  // swapAnimationCurve: Curves.elasticIn,
                  BarChartData(
                    minY: 0,
                    maxY: widget.dateType == DateType.day ? 150 : 800,
                    barTouchData: barTouchData,
                    titlesData: titlesData,
                    gridData: gridData,
                    borderData: borderData,
                    groupsSpace: barsSpace,
                    barGroups: bars,
                    extraLinesData: ExtraLinesData(
                        verticalLines: showingTooltipOnBars
                            .map(
                              (index) => VerticalLine(x: bars[index].barRods.map((e) => e.toY).reduce((value, element) => value + element)),
                            )
                            .toList()),
                  ),
                );
              }),
            ),
          );
  }

  get gridData => FlGridData(
        show: true,
        drawVerticalLine: false,
        getDrawingVerticalLine: (value) => FlLine(
          color: ColorConst.secondaryBgColor,
          dashArray: [8, 4],
          strokeWidth: 1,
        ),
        drawHorizontalLine: true,
        horizontalInterval: widget.dateType == DateType.day ? 40 : 250,
        getDrawingHorizontalLine: (value) => FlLine(
          color: ColorConst.secondaryBgColor,
          strokeWidth: 1,
          dashArray: [8, 4],
        ),
      );

  get barTouchData => BarTouchData(
        enabled: true,
        longPressDuration: const Duration(milliseconds: 200),
        handleBuiltInTouches: false,
        touchCallback: (FlTouchEvent event, BarTouchResponse? response) {
          if (event.isInterestedForInteractions && response != null && response.spot != null) {
            setState(() {
              touchedGroupIndex = response.spot!.touchedBarGroupIndex;
              isTouched = true;
            });
          } else {
            setState(() {
              touchedGroupIndex = -1;
              isTouched = false;
            });
          }
        },
        touchTooltipData: BarTouchTooltipData(
          fitInsideHorizontally: true,
          fitInsideVertically: true,
          direction: TooltipDirection.top,
          tooltipPadding: EdgeInsets.zero,
          tooltipMargin: 0,
          tooltipBgColor: Colors.grey.withOpacity(0.4),
          getTooltipItem: (BarChartGroupData group, int groupIndex, BarChartRodData rod, int rodIndex) {
            SleepSummary ss = widget.summaryList[touchedGroupIndex];
            return BarTooltipItem(
              dateTooltipText(ss),
              TextStyle(fontSize: 36.sp),
            );
          },
        ),
      );

  String dateTooltipText(SleepSummary ss) {
    ss.sleepTimeSum = ss.models.map((e) => e.sleepTime ?? 0).reduce((value, element) => value + element);
    String date = DateTool.mdFormat(DateTime.fromMillisecondsSinceEpoch(ss.models.last.endTime! * 1000));
    String hm = DateTool.second2HM(ss.sleepTimeSum * 60, isEasy: false);
    return '$date $hm';
  }

  FlTitlesData get titlesData => FlTitlesData(
        show: true,
        bottomTitles: AxisTitles(
          sideTitles: SideTitles(
            showTitles: true,
            getTitlesWidget: bottomTitles,
          ),
        ),
        leftTitles: const AxisTitles(
          sideTitles: SideTitles(showTitles: false),
        ),
        topTitles: const AxisTitles(
          sideTitles: SideTitles(showTitles: false),
        ),
        rightTitles: const AxisTitles(
          sideTitles: SideTitles(showTitles: false),
        ),
      );

  FlBorderData get borderData => FlBorderData(
      show: true,
      border: Border(
        left: BorderSide(width: 1.w, color: const Color(0xff37434d)),
        bottom: BorderSide(width: 1.w, color: const Color(0xff37434d)),
      ));

  Widget bottomTitles(double value, TitleMeta meta) {
    int len = titles.length;
    int idx = value.toInt();
    String text;

    if (len > 0) {
      if (len == 7) {
        text = idx < len ? titles.elementAt(idx) : '';
      } else {
        if (idx == 0) {
          text = titles.first;
        } else if (idx == len ~/ 2) {
          text = titles.elementAt(len ~/ 2);
        } else if (idx == len - 1) {
          text = titles.last;
        } else {
          text = '';
        }
      }
    } else {
      text = '';
    }

    return SideTitleWidget(
      axisSide: meta.axisSide,
      child: Text(text, style: TextStyle(color: ColorConst.secondaryFontColor, fontSize: 36.sp)),
    );
  }

  List<BarChartGroupData> getBarGroupsData(double barsWidth, double barsSpace) {
    List<BarChartGroupData> bars = [];
    for (int i = 0; i < widget.summaryList.length; i++) {
      List<SleepModel> models = widget.summaryList[i].models;
      bars.add(
        BarChartGroupData(
          x: i,
          barsSpace: barsSpace,
          groupVertically: true,
          barRods: getRodData(models, barsWidth),
          // 因为是堆叠起来的柱状图，需要将tooltip显示在最上面的柱状图
          showingTooltipIndicators: touchedGroupIndex == i ? [widget.summaryList[i].models.length - 1] : [],
        ),
      );
    }
    return bars;
  }

  List<BarChartRodData> getRodData(List<SleepModel> models, barsWidth) {
    Map<int, List<SleepModel>> map = {for (var e in models) e.sleepType!: models.where((item) => item.sleepType == e.sleepType).toList()};

    List<BarChartRodData> rods = [];
    int fromY = 0;
    int maxY = 0;
    for (var entry in map.entries) {
      // 排除掉零星小睡
      // entry.value.removeWhere((element) => element.isSnooze!);
      int temp = (entry.value.map((e) => e.sleepTime).reduce((value, element) => value! + element!) ?? 0);
      if (temp == 0) {
        continue;
      }

      maxY = maxY + temp;
      rods.add(
        BarChartRodData(
          width: barsWidth,
          fromY: fromY.toDouble(),
          toY: maxY.toDouble(),
          color: getColor(entry.key),
          // borderSide: BorderSide(
          //   color: Colors.black.withOpacity(.4),
          //   width: isTouched ? 2.w : 0,
          // ),
          borderRadius: BorderRadius.only(topLeft: Radius.circular(1.r), topRight: Radius.circular(1.r)),
        ),
      );
      fromY = maxY;
    }
    return rods;
  }

  getColor(int type) {
    switch (type) {
      case 1: //深睡
        return deepSleepColor;
      case 2: //浅睡
        return lightSleepColor;
      case 3: //清醒
        return awakeColor;
      case 4: //快速眼动
        return remColor;
      default:
        return napsColor;
    }
  }
}
